/* 显示分数 */
var mark = document.querySelector(".mark");
/* 分数变量 */
var marks = 0;
/* 再来一局 */
var again = document.querySelector(".again");

/* 常量，不可修改 */
/* 一次走的距离 */
var STEP = 28;

/* 容器一共18行，10列 */
var ROW_COUNT = 18, COL_COUNT = 10;

/* 记录所有出现的块元素的位置 k=行_列 ：v=块元素 */
var fixedBlocks = {}

/* 创建每个模型的数据源 */
var MODELS = [
  /* L型模型，里面每个盒子相对16宫格的坐标 */
  {
    0: { row: 2, col: 0 },
    1: { row: 2, col: 1 },
    2: { row: 2, col: 2 },
    3: { row: 1, col: 2 }
  },
  // 第2个模型数据源(凸)
  {
    0: {
      row: 1,
      col: 1
    },
    1: {
      row: 0,
      col: 0
    },
    2: {
      row: 1,
      col: 0
    },
    3: {
      row: 2,
      col: 0
    }
  },
  // 第3个模型数据源(田)
  {
    0: {
      row: 1,
      col: 1
    },
    1: {
      row: 2,
      col: 1
    },
    2: {
      row: 1,
      col: 2
    },
    3: {
      row: 2,
      col: 2
    }
  },
  // 第4个模型数据源(一)
  {
    0: {
      row: 0,
      col: 0
    },
    1: {
      row: 0,
      col: 1
    },
    2: {
      row: 0,
      col: 2
    },
    3: {
      row: 0,
      col: 3
    }
  },
  // 第5个模型数据源(Z)
  {
    0: {
      row: 1,
      col: 1
    },
    1: {
      row: 1,
      col: 2
    },
    2: {
      row: 2,
      col: 2
    },
    3: {
      row: 2,
      col: 3
    }
  }

]

/* 变量，当前使用的模型 */
var currentModel = {}
/* 变量，16宫格的位置 */
var currentX = 0, currentY = 0;

/* 根据模型数据源来创建块元素 */
function createModel() {
  /* 判断满足游戏结束条件没 */
  if (isGameOver()) {
    ganmeOver();
    return;
  }
  /* 先确定创建哪个模型 */
  currentModel = MODELS[_.random(0, MODELS.length - 1)];
  /* 重新初始化16宫格的位置 */
  currentX = 0;
  currentY = 0;
  /* 来个随机颜色 */
  let color = new Array("#69c11d", "#f83a56", "#3c6df0", "	#24b4f0", "#f8dc8f", "#b7239f", "#ff8f28");
  let color1 = new Array("#52af00", "#d0122e", "#1743c0", "	#0f9bd6", "#ffc435", "#aa208f", "#dc5d00");
  let i = Math.floor(Math.random() * color.length)
 
  /* 遍历对象，生成数量的块元素 */
  for (var key in currentModel) {
    var divKuai = document.createElement("div");
    divKuai.className = "kuai";
    /*                 divKuai.style.backgroundColor = color ; */
    // for (let i = 0; i < color.length; i++) {
    divKuai.style.cssText = `
         border: 1px solid ${color[i]};
         background-color: ${color1[i]};
         border-radius: 3px;`
      document.getElementById("container").appendChild(divKuai);
    // }
  }
  /* 定位 */
  locationBlocks();
  /* 自动下落 */
  autoDown();
}

/* 根据创建好的块元素给他定位位置，生成相应的模型 */
function locationBlocks() {
  /* 判断越界 */
  checkBound();
  /* 得到当前所有块元素 */
  var blocks = document.getElementsByClassName("kuai");
  for (var i = 0; i < blocks.length; i++) {
    /* 每个块元素 */
    var oneBlock = blocks[i];
    /* 得到每个块元素的坐标,16宫格位置加上本身相对16宫格位置 */
    var locationKuai = currentModel[i];
    oneBlock.style.top = (locationKuai.row + currentY) * STEP + "px";
    oneBlock.style.left = (locationKuai.col + currentX) * STEP + "px";
  }
}


/*  入口方法 */
function rukou() {
  onKeyDown();
  createModel();
}


/* 用户点击键盘事件 */
function onKeyDown() {
  document.addEventListener('keydown', function (event) {

    switch (event.keyCode) {
      case 38: console.log("shang");
        rotate();
        break;
      case 39: console.log("you");
        move(1, 0);
        break;
      case 40: console.log("xia");
        move(0, 1);
        break;
      case 37: console.log("zuo");
        move(-1, 0);
        break;

    }
  })
}

/* 移动函数 */
function move(x, y) {
  /* 判断触碰，就是判断活动中的模型将要移动到的位置是否存在已经固定的模型（块元素） */
  if (isMeet(currentX + x, currentY + y, currentModel)) {
    /* 若发生触碰，且由y轴引起，那么说明模型的底部发生触碰了，那么该停下了 */
    if (y !== 0) {
      fixedBottomModel();
    }
    /* 直接return掉move方法，不再执行 */
    return;
  }
  /* 移动16宫格 */
  currentX = currentX + x;
  currentY = currentY + y;
  locationBlocks();
}

/* 旋转模型函数 */
function rotate() {
  // 克隆一下 currentModel  用引入的js文件里的方法
  var cloneCurrentModel = _.cloneDeep(currentModel);
  /* 算法：移动后的行=移动前的列  移动后的列=3-移动前的行 */
  /* 得到当前使用的模型数据源里的块元素的坐标 */
  for (var key in cloneCurrentModel) {
    var blocksModel = cloneCurrentModel[key];
    /* 实现算法进行变换 */
    let temp = blocksModel.row;
    blocksModel.row = blocksModel.col;
    blocksModel.col = 3 - temp;
  }
  /* 判断触碰，就是判断活动中的模型将转的地方是否存在已经固定的模型（块元素） */
  if (isMeet(currentX, currentY, cloneCurrentModel)) {
    return;
  }
  /* 接收了这次旋转 */
  currentModel = cloneCurrentModel;

  locationBlocks();
}

/* 控制模型只能在游戏区域里移动 */
function checkBound() {
  /* 模型可活动的边界 */
  var leftBound = 0, rightBound = COL_COUNT, bottomBound = ROW_COUNT;
  /* 当块元素超出边界后，让16宫格退一步，这样一走一退相互抵消 */
  for (var key in currentModel) {
    var blocksModel = currentModel[key];
    /* 左侧边界 */
    if ((blocksModel.col + currentX) < leftBound) {
      currentX++;
    }
    /* 右侧边界 */
    if ((blocksModel.col + currentX) >= rightBound) {
      currentX--;
    }
    /* 底侧边界 */
    if ((blocksModel.row + currentY) >= bottomBound) {
      currentY--;
      /* 固定在底部 */
      fixedBottomModel();
    }

  }
}

/* 当模型到达底部时固定在底部 */
function fixedBottomModel() {
  /* 1.改变模型颜色样式 */
  var activityModels = document.getElementsByClassName("kuai");
  /* 因为js特效，要从后往前遍历 */
  for (var i = activityModels.length - 1; i >= 0; i--) {
    var activityModel = activityModels[i];
    /* 让其不再移动，改变类名就行，这样位置函数将对其无效了 */
    activityModel.className = "ding";
    /* 把其放在记录块元素位置的变量中 */
    var blocksModel = currentModel[i];
    fixedBlocks[(currentY + blocksModel.row) + "_" + (currentX + blocksModel.col)] = activityModel;

  }
  /* 判断一行是否被铺满 */
  isRemoveLine();

  /* 创建新模型 */
  createModel();
}

/* 判断模型之间的触碰问题 */
/* x，y为16宫格将要去到的位置，model表示当前模型将要完成的变化 */
function isMeet(x, y, model) {
  /* 判断触碰，就是判断活动中的模型将要移动到的位置是否存在已经固定的模型（块元素） */
  /* 该位置是否存在块元素？ 只有一个return会生效*/
  for (var k in model) {
    var blockModel = model[k];
    if (fixedBlocks[(y + blockModel.row) + "_" + (x + blockModel.col)]) {
      return true;
    }
  }
  return false;
}

/* 判断一行是否被铺满 */
function isRemoveLine() {
  /* 判断某行中，每一列是否都存在块元素，是则清理 */
  /* 遍历所有行所有列 */
  for (var i = 0; i < ROW_COUNT; i++) {
    /* 假设当前行铺满，设flag=true */
    var flag = true;
    for (var j = 0; j < COL_COUNT; j++) {
      /* 当前行没铺满 */
      if (!fixedBlocks[i + "_" + j]) {
        flag = false;
        break;
      }
    }
    /* 当某行铺满,flag==true */
    if (flag) {
      removeLine(i);
    }
  }
}

/* 清理被铺满的一行 */
function removeLine(line) {
  /* 删除该行的块元素 */
  for (var i = 0; i < COL_COUNT; i++) {
    document.getElementById("container").removeChild(fixedBlocks[line + "_" + i]);
    /* 数据源也删除 */
    fixedBlocks[line + "_" + i] = null;
  }
  downLine(line);
  /* 加分数 */
  marks++;
  mark.innerHTML = "分数：" + marks;

}

/* 被清理行上面的块元素下落 */
function downLine(line) {
  /* 遍历被清理行上的所有行 */
  for (var i = line - 1; i >= 0; i--) {
    /* 该行的所有列 */
    for (var j = 0; j < COL_COUNT; j++) {
      if (!fixedBlocks[i + "_" + j]) continue;
      /* 被清理行上面的块元素数据源所在行数+1 */
      fixedBlocks[(i + 1) + "_" + j] = fixedBlocks[i + "_" + j];
      /* 让块元素下落 */
      fixedBlocks[(i + 1) + "_" + j].style.top = (i + 1) * STEP + 'px';
      /* 清理之前块元素 */
      fixedBlocks[i + "_" + j] = null;
    }
  }
}

/* 模型自动下落 */

var mInterval = null;

function autoDown() {
  if (mInterval) {
    clearInterval(mInterval);
  }
  mInterval = setInterval(function () {
    move(0, 1);
  }, 500)
}

/* 判断游戏结束 */
function isGameOver() {
  /* 第0行也有元素时结束游戏 */
  for (var i = 0; i < COL_COUNT; i++) {
    if (fixedBlocks["0_" + i]) {
      return true;
    }
  }
  return false;
}
/* 结束游戏 */
function ganmeOver() {
  /* 停止定时器 */
  if (mInterval) {
    clearInterval(mInterval);
  }
  /* 弹出对话框 */
  alert("游戏结束!   分数为：" + marks + "。");
}

/* 点击再来一局 */
again.addEventListener('click', function () {

  /* 简单粗暴直接刷新好吧 */
  location.reload(true);
})